03. 函数定义-算数平均收益率计算

本章学习目标

  • 理解函数在金融编程中的核心作用
  • 掌握 deflambda 两种函数定义方式
  • 学会计算算术平均收益率
  • 了解算术平均与几何平均的区别
  • 能够编写带参数验证的健壮函数

函数:编程中的基本抽象单元

函数将一系列操作封装起来,使代码更加:

  • 模块化:每个函数专注做一件事
  • 可重用:一次编写,多次调用
  • 易维护:修改一处,全局生效

在金融计算中,收益率、波动率、VaR 等指标需要反复计算,函数是实现这一目标的关键工具。

函数体现的三种核心编程思想

函数体现的三种核心编程思想 展示抽象、分解、复用三个概念的示意图 抽象 Abstraction 隐藏实现细节 只暴露接口 🔒 分解 Decomposition 将复杂问题 分解为简单子问题 🧩 复用 Reuse 一次编写 多次调用 ♻️

算术平均收益率:最基本的金融指标

对于收益率序列 \(r_1, r_2, \ldots, r_n\),算术平均定义为:

\[ \large{ \bar{r} = \frac{1}{n} \sum_{i=1}^{n} r_i = \frac{r_1 + r_2 + \cdots + r_n}{n} } \]

金融含义:算术平均收益率适用于——

  • 单期期望收益率的估计
  • 投资组合绩效评估
  • 风险调整后收益率的基准

算术平均的关键数学性质

  • 线性性\(\overline{aX + bY} = a\bar{X} + b\bar{Y}\)
  • 最小二乘性:算术平均使误差平方和 \(\sum(x_i - \bar{x})^2\) 最小
  • 敏感性:对极端值敏感,受异常值影响大

易混淆概念:算术平均 vs. 几何平均

特性 算术平均 几何平均
公式 \(\bar{r}_A = \frac{1}{n}\sum r_i\) \(\bar{r}_G = [\prod(1+r_i)]^{1/n} - 1\)
应用场景 单期期望收益 多期复利增长
数值关系 \(\bar{r}_A \geq \bar{r}_G\) 波动率越大,差距越大
金融含义 期初财富的期望增长率 期末财富的实际增长率

关键理解:想知道”平均每期赚多少”→ 算术平均;计算”长期复利增长”→ 几何平均。

Python函数定义:def 关键字

def 是 Python 中最常用的函数定义方式:

def function_name(parameters):
    """文档字符串(Docstring)"""
    function_body
    return value
  • def:函数定义关键字
  • parameters:参数列表,多个参数用逗号分隔
  • return:返回值,无 return 则返回 None

def 定义算术平均函数

# 用def定义计算算术平均数的标准函数
def arithmetic_mean(numbers):
    """计算算术平均数"""
    return sum(numbers) / len(numbers)

# 测试函数
data = [1, 2, 3, 4, 5]
print(f'算术平均值: {arithmetic_mean(data)}')
算术平均值: 3.0
  • sum(numbers):计算列表元素总和
  • len(numbers):获取列表长度
  • /:执行浮点除法(Python 3 特性)

Python函数定义:lambda 表达式

lambda 用于定义匿名函数,适合简单的单行函数:

# 语法格式
lambda parameters: expression
# lambda定义算术平均函数
arithmetic_mean_lambda = lambda x: sum(x) / len(x)

data = [1, 2, 3, 4, 5]
print(f'lambda计算结果: {arithmetic_mean_lambda(data)}')
lambda计算结果: 3.0

lambda 的限制:只能包含单个表达式,不能包含语句(如 ifforwhile)。

def vs. lambda:如何选择?

def与lambda的对比 展示def和lambda两种函数定义方式的适用场景对比 def 标准函数 ✅ 可包含多条语句 ✅ 支持文档字符串 ✅ 可复杂逻辑与异常处理 ✅ 可读性强,便于调试 适合:复杂逻辑、生产代码 lambda 匿名函数 ⚡ 仅支持单个表达式 ⚡ 无文档字符串 ⚡ 代码简洁紧凑 ⚡ 常配合 map/filter 使用 适合:简单计算、临时函数

⭐ 平台任务:计算上证指数算术平均收益率

Listing 1
# ⚠️ 平台原始代码 - 请原样输入至教学平台(注释除外),平台才会判定答案正确
A_mean=lambda x:sum(x)/len(x)  # 定义匿名函数A_mean
sh000001=[26.468,-10.7081,2.8477,43.5348,13.4337]  # 定义列表sh000001
print(round(A_mean(sh000001),2))  # 输出四舍五入后的计算结果
15.12

平台代码逐步解析

第一步:定义 lambda 函数

  • A_mean = lambda x: sum(x) / len(x)
  • 参数 x 是一个列表,sum(x) 求和,len(x) 求长度

第二步:创建数据

  • sh000001 列表包含上证指数5年的年收益率(%)

第三步:计算并输出

  • sum = 75.5762len = 5
  • mean = 75.5762 / 5 = 15.11524
  • round(15.11524, 2)15.12

金融含义:上证指数平均收益率 15.12%

上证指数在样本期内的平均年收益率约为 15.12%,这意味着:

  • 期望收益:基于历史数据,投资者可期望每年获得约 15% 的回报
  • 风险评估:需结合波动率(标准差)评估风险调整后收益
  • 基准比较:可与无风险利率、其他市场指数进行比较

进阶:带参数验证的函数

def calculate_mean_return(returns, decimals=2):
    """
    计算算术平均收益率
    参数:
        returns (list): 收益率序列
        decimals (int): 保留小数位数,默认为2
    """
    # 参数验证:检查输入有效性
    if not returns:
        raise ValueError('收益率列表不能为空')
    if not all(isinstance(r, (int, float)) for r in returns):
        raise ValueError('收益率必须为数值类型')
    # 计算并返回
    mean = sum(returns) / len(returns)
    return round(mean, decimals)

# 使用示例
sh000001 = [26.468, -10.7081, 2.8477, 43.5348, 13.4337]
result = calculate_mean_return(sh000001, decimals=3)
print(f'上证指数平均收益率: {result:.3f}%')
上证指数平均收益率: 15.115%

生产级函数的三个关键要素

  1. 文档字符串(Docstring)
    • 描述函数功能、参数类型、返回值
  2. 参数验证
    • 检查输入有效性,提供清晰的错误信息
    • 防止程序因非法输入而崩溃
  3. 默认参数
    • 提供合理默认值(如 decimals=2
    • 增强函数灵活性和使用便利性

lambda 进阶:配合 map 批量计算

# 投资组合中各股票的收益率
portfolio_returns = {
    'Stock A': [0.05, 0.03, -0.02, 0.04, 0.06],
    'Stock B': [0.08, 0.02, 0.01, -0.03, 0.05],
    'Stock C': [-0.01, 0.04, 0.07, 0.02, 0.03]
}

# 用lambda + map批量计算每只股票的平均收益率
mean_calculator = lambda returns: round(sum(returns) / len(returns), 4)
mean_returns = list(map(mean_calculator, portfolio_returns.values()))

for name, mean_r in zip(portfolio_returns.keys(), mean_returns):
    print(f'{name} 平均收益率: {mean_r}')
Stock A 平均收益率: 0.032
Stock B 平均收益率: 0.026
Stock C 平均收益率: 0.03

lambda 进阶:配合 filter 筛选数据

# 使用filter筛选正收益
returns_data = [0.05, -0.02, 0.03, -0.01, 0.08, -0.04]

positive_returns = list(filter(lambda r: r > 0, returns_data))
negative_returns = list(filter(lambda r: r < 0, returns_data))

print(f'正收益: {positive_returns}')
print(f'负收益: {negative_returns}')
print(f'胜率: {len(positive_returns)/len(returns_data):.1%}')
正收益: [0.05, 0.03, 0.08]
负收益: [-0.02, -0.01, -0.04]
胜率: 50.0%
  • filter(function, iterable) 根据条件筛选元素
  • 在金融中可用于筛选盈利交易、亏损交易等

lambda 进阶:配合 reduce 计算累积收益

from functools import reduce

# 计算累积收益率(复利效果)
returns = [0.05, 0.03, -0.02, 0.04]

# reduce逐步累积:1 → 1*(1+0.05) → 1.05*(1+0.03) → ...
cumulative_return = reduce(lambda x, y: x * (1 + y), returns, 1) - 1

print(f'各期收益率: {returns}')
print(f'算术平均收益率: {sum(returns)/len(returns):.4f}')
print(f'累积收益率: {cumulative_return:.4f}')
各期收益率: [0.05, 0.03, -0.02, 0.04]
算术平均收益率: 0.0250
累积收益率: 0.1023
  • reduce 对序列进行累积计算
  • 初始值 1 代表初始本金
  • 最终结果减 1 得到净收益率

算术平均的局限性

算术平均虽然简单直观,但在金融应用中存在重要局限:

  1. 极端值敏感:一个极端值会显著拉高/拉低平均值
  2. 不适用于多期增长:会高估长期复利增长
  3. 分布假设:隐含假设收益率对称分布,但实际金融收益常呈偏态分布

改进方案:稳健统计量

import numpy as np
from scipy import stats

# 包含极端值的收益率数据
returns = [0.05, 0.03, 0.04, 0.50, 0.02, -0.10, 0.06]

# 四种集中趋势度量的比较
arithmetic_mean = np.mean(returns)
median = np.median(returns)
trimmed_mean = stats.trim_mean(returns, 0.1)
winsorized_mean = stats.mstats.winsorize(
    np.array(returns), limits=[0.1, 0.1]
).mean()

print(f'算术平均: {arithmetic_mean:.4f}')
print(f'中位数:   {median:.4f}')
print(f'截尾平均: {trimmed_mean:.4f}')
print(f'缩尾平均: {winsorized_mean:.4f}')
算术平均: 0.0857
中位数:   0.0400
截尾平均: 0.0857
缩尾平均: 0.0857

如何选择合适的统计量?

场景 推荐统计量 理由
正常分布数据 算术平均 最优无偏估计
含极端值 中位数/截尾平均 稳健性强
投资组合基准 算术平均 与 CAPM 模型一致
长期绩效评估 几何平均 反映真实复利增长

本章总结

  • 函数定义def(复杂逻辑)vs. lambda(简单计算)
  • 算术平均\(\bar{r} = \frac{1}{n}\sum r_i\),适用于单期期望收益估计
  • 高阶函数map(批量计算)、filter(筛选)、reduce(累积)
  • 稳健统计:面对极端值时,考虑中位数或截尾平均
  • 最佳实践:生产代码应包含文档字符串和参数验证